package com.lancoo.ccas52.arrangecourse.clashesprocess;

import com.lancoo.ccas52.arrangecourse.entities.ClassHour;
import com.lancoo.ccas52.arrangecourse.entities.CourseUnit;
import com.lancoo.ccas52.arrangecourse.entities.TimeslotRoom;
import com.lancoo.ccas52.entity.ScheduleConflictInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * @Description 冲突处理
 * @Author Fortysun
 * @Date 2023-03-29 19:07
 */
@Slf4j
@Configuration
public class ClashesProcess {

    //计算计算冲突数
    private ClashesCompute clashesCompute;
    //记录冲突列表信息
    private ClashesRecord clashesRecord;
    //记录教室课时冲突
    private TimeslotRoomClashesRecord timeslotRoomClashesRecord;

    public ClashesProcess() {
        //初始化
        clashesCompute = new ClashesCompute();
        clashesRecord = new ClashesRecord();
        timeslotRoomClashesRecord = new TimeslotRoomClashesRecord();
    }

    /**
     * 检测教室容量不足
     * @param classHour
     * @return
     */
    protected boolean isRoomCapacityClash(ClassHour classHour) {
        //获取教室课时分组信息
        TimeslotRoom timeslotRoom = classHour.getTimeslotRoom();
        //如果教室课时分组对象为空，说明此授课类型教学班没有分配教室课时分组，
        //那么就不存在教室容量不足的问题
        if (timeslotRoom == null) {
            return false;
        }

        //获取教学班人数
        Integer teachingClassSize = classHour.getCourseUnit().getTeachingClassSize();

        //获取教室容量
        Integer roomCapacity = timeslotRoom.getCapacity();
        if (roomCapacity == null) {
            roomCapacity = 0;
        }
        //分配的教室容量不符和要求
        if (roomCapacity < teachingClassSize) {
            return true;
        }

        return  false;
    }

    /**
     * 记录已经分配了教室课时的
     * @param classHourMap 全部课表数据map
     * @param clashesClassHourList 存在冲突的课表数据
     * @param conflictMap 冲突信息记录的map，map的key为排课单元id，即CourseUnitId
     * @return
     */
    public Map<Integer, List<ScheduleConflictInfo>> recordTimeslotRoomClashes(ConcurrentHashMap<String,
              CopyOnWriteArrayList<ClassHour>> classHourMap,
              CopyOnWriteArrayList<ClassHour> clashesClassHourList,
              Map<Integer, List<ScheduleConflictInfo>> conflictMap) {
        //遍历冲突的教学班排课单元列表，找出冲突的教学班，将对应的冲突信息，写入冲突列表
        for (ClassHour classHour : clashesClassHourList) {
            //存在冲突的教学班排课单元，分配的教室课时分组信息；
            TimeslotRoom timeslotRoom = classHour.getTimeslotRoom();
            if (timeslotRoom != null) {
//                    //找出可课时相同的课表对象列表，用来进行排课
//                    conflictMap=recordClashesByRoomType(
//                            classHourMap.get(timeslotRoom.getTimeslotCode()),
//                            classHour, conflictMap);
                //找出可课时相同的课表对象列表，用来进行排课冲突的记录
                conflictMap = timeslotRoomClashesRecord.recordClashes(
                        classHourMap.get(timeslotRoom.getTimeslotCode()),
                        classHour, conflictMap);
            }
        }

        return conflictMap;
    }
    /**
     * 筛选出，指定对象的，所学的教室类型的数据，去进行冲突匹配
     * 即：匹配冲突，只需要针对相同教室类型的课程课表信息，进行比较。无需比较不同教室类型的数据
     * @param classHourA 课时对象
     * @param classHourList 课时对象列表
     * @param conflictMap 冲突信息记录的map
     * @return
     */
    private Map<Integer, List<ScheduleConflictInfo>> recordClashesByRoomType(CopyOnWriteArrayList<ClassHour> classHourList,
                                                                             ClassHour classHourA,
                                                                             Map<Integer, List<ScheduleConflictInfo>> conflictMap) {
        if (classHourList != null && !classHourList.isEmpty()) {
            //按教学班所需的教室类型，对列表进行分组，存入map，key为roomtype
            Map<Integer, CopyOnWriteArrayList<ClassHour>> roomTypeMap = classHourList.stream()
                    .collect(Collectors.groupingBy(
                            classHour -> classHour.getCourseUnit().getRoomType(), // 使用 getRoomType() 方法
                            ConcurrentHashMap::new,
                            Collectors.mapping(classHour -> classHour, Collectors.toCollection(CopyOnWriteArrayList::new))
                    ));

            //存在冲突的教学班排课单元，分配的教室课时分组信息；
            TimeslotRoom timeslotRoom = classHourA.getTimeslotRoom();
            //如果教学班已经分配了教室课时
            if (timeslotRoom != null) {
                //获取指定教室类型的，课表信息
                CopyOnWriteArrayList<ClassHour> roomTypeList = roomTypeMap.get(timeslotRoom.getRoomType());
                conflictMap=timeslotRoomClashesRecord.recordClashes(
                        roomTypeList,
                        classHourA, conflictMap);
            }
        }

        return conflictMap;
    }


    /**
     * 统计冲突的数量
     * @param classHourMap 上课课时map；
     * @param clashesRecordList 冲突记录列表
     * @return
     */
    public List<ScheduleConflictInfo> recordClashes(ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap,
                             List<ScheduleConflictInfo> clashesRecordList) {
        //记录不同类型的课时，对应的冲突列表
        for (Map.Entry entry : classHourMap.entrySet()) {
            //记录每个课时对应的冲突列表
            clashesRecordList.addAll(recordTimeslotCodeClashes((CopyOnWriteArrayList<ClassHour>)entry.getValue(), clashesRecordList));
        }

        return clashesRecordList;
    }

    /**
     * 统计冲突的数量
     * @param classHourList 上课课时列表；
     * @param clashesRecordList 冲突记录列表
     * @return
     */
    public List<ScheduleConflictInfo> recordTimeslotCodeClashes(CopyOnWriteArrayList<ClassHour> classHourList,
                                                    List<ScheduleConflictInfo> clashesRecordList) {
        if (classHourList != null && classHourList.size() > 0) {
            //循环遍历列表，进行冲突的判断和记录
            for (ClassHour classHourA : classHourList) {

                //如果教室课时分组对象为空，说明此授课类型教学班没有分配教室课时分组，
                //那么就不存在冲突检测的问题
                if (classHourA.getTimeslotRoom() == null) {
                    //当前排课课表单元，分配的教学班排课单元
                    CourseUnit curCourseUnit = classHourA.getCourseUnit();

                    //记录教学班上课单元未分配教室和课时的冲突
                    clashesRecordList.add(clashesRecord.initConflictInfo(curCourseUnit.getTaskId(),
                            5,
                            curCourseUnit.getTeachingClassId(),
                            -1L,
                            "",
                            -1L,
                            curCourseUnit.getClassWeeks(),
                            "教室课时未分配---教学班："+ curCourseUnit.getTeachingClassName()
                                    + ",未分配教室和课时"));

                    //直接跳过本次循环，进入下一次循环
                    continue;
                }

                clashesRecord.recordClashes(classHourList, classHourA, clashesRecordList);
            }
        }

        return clashesRecordList;
    }

    /**
     * 统计冲突的数量
     * @param classHourMap 上课课时map；
     * @return
     */
    public int calcClashes(ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap) {
        int clashes = 0;
        //统计不同类型的课时，对应的课时的冲突次数
        for (Map.Entry entry : classHourMap.entrySet()) {
            clashes+= calcTimeslotCodeClashes((CopyOnWriteArrayList<ClassHour>)entry.getValue());
        }

        return clashes;
    }

    /**
     * 统计冲突的数量
     * @param classHourList 指定课时的上课课时列表；
     * @return
     */
    public int calcTimeslotCodeClashes(CopyOnWriteArrayList<ClassHour> classHourList) {
        int clashes = 0;
        for (ClassHour classHourA : classHourList) {

            //如果教室课时分组对象为空，说明此授课类型教学班没有分配教室课时分组，
            //那么就不存在冲突检测的问题
            if (classHourA.getTimeslotRoom() == null) {
                //直接跳过本次循环，进入下一次循环
                continue;
            }
            clashes = clashesCompute.computeClashes(classHourList, classHourA, clashes);
        }

        return clashes;
    }
}